package com.mg.framework.kernel;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;

public class MoveController extends Actor implements Touchable {

	private boolean reset = false;

	private float cX = -1;
	private float cY = -1;
	private float pCX = -1;
	private float pCY = -1;
	private float outerRadius = -1;
	private float innerRadius = -1;

	private Paint paint = null;
	private Paint outerPaint = null;
	private Paint innerPaint = null;

	private Canvas canvas = null;

	private int pointerIndex = -1;
	private int pointerId = -1;
	private int currentPointerId = -1;
	private int currentPointerIndex = -1;

	public MoveController(Screen screen, int width, int height) {
		super(screen, width, height);
		this.x = 2;
		this.y = this.screen.getHeight() - 2 - height;
		this.pCX = this.cX = width / 2;
		this.pCY = this.cY = height / 2;

		this.outerRadius = this.width / 2;
		this.innerRadius = this.width / 4;

		this.paint = new Paint();
		this.paint.setAntiAlias(true);
		this.paint.setAlpha(120);

		this.outerPaint = new Paint();
		this.outerPaint.setAntiAlias(true);
		this.outerPaint.setColor(Color.WHITE);

		this.innerPaint = new Paint();
		this.innerPaint.setAntiAlias(true);
		this.innerPaint.setColor(Color.RED);

		this.canvas = new Canvas(this.bitmap);
	}

	@Override
	public void gameUpdate() {
		this.canvas.drawCircle(cX, cY, outerRadius, outerPaint);
		this.canvas.drawCircle(pCX, pCY, innerRadius, innerPaint);

		float xOffset = pCX - cX;
		float yOffset = pCY - cY;
		if (xOffset != 0 || yOffset != 0) {
			((ControllerScreen) this.screen).handleMove(xOffset, yOffset);
			this.reset = true;
		} else if (this.reset) {
			((ControllerScreen) this.screen).handleReset();
			this.reset = false;
		}
	}

	@Override
	public void screenUpdate(Canvas canvas) {
		canvas.drawBitmap(this.bitmap, this.x, this.y, paint);
	}

	@Override
	public void onTouchEvent(MotionEvent event) {
		switch (event.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_POINTER_DOWN:
			if (this.currentPointerId == -1) {
				this.pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
				this.pointerId = event.getPointerId(pointerIndex);
				this.currentPointerId = pointerId;
				this.currentPointerIndex = event
						.findPointerIndex(currentPointerId);
				moveFlag(event.getX(this.currentPointerIndex),
						event.getY(this.currentPointerIndex));
			}
			break;
		case MotionEvent.ACTION_MOVE:
			if (this.currentPointerId != -1) {
				this.currentPointerIndex = event
						.findPointerIndex(currentPointerId);
				moveFlag(event.getX(this.currentPointerIndex),
						event.getY(this.currentPointerIndex));
			}
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_UP:
			this.pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
			this.pointerId = event.getPointerId(pointerIndex);
			if (this.currentPointerId != -1
					&& this.currentPointerId == this.pointerId) {
				this.pCX = this.cX;
				this.pCY = this.cY;
				this.currentPointerIndex = -1;
				this.currentPointerId = -1;
			}
			break;
		}
	}

	private void setPointerXY(float centerX, float centerY, float R,
			double Radian) {
		this.pCX = (float) (R * Math.cos(Radian)) + centerX;
		this.pCY = (float) (R * Math.sin(Radian)) + centerY;
	}

	private double getRadian(float px1, float py1, float px2, float py2) {
		float x = px2 - px1;
		float y = py1 - py2;
		float Hypotenuse = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
		float cosAngle = x / Hypotenuse;
		float Radian = (float) Math.acos(cosAngle);
		if (py2 < py1) {
			Radian = -Radian;
		}
		return Radian;
	}

	@Override
	public boolean isTouched(MotionEvent event) {
		if (this.currentPointerId == -1) {
			this.pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
			return isInArea(event.getX(this.pointerIndex),
					event.getY(this.pointerIndex), this.outerRadius);
		} else {
			switch (event.getAction() & MotionEvent.ACTION_MASK) {
			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_POINTER_UP:
				this.pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
				this.pointerId = event.getPointerId(pointerIndex);
				if (this.currentPointerId == this.pointerId) {
					return true;
				}
				break;
			}
			return isInArea(event.getX(this.currentPointerIndex),
					event.getY(this.currentPointerIndex), this.outerRadius);
		}
	}

	private boolean isInArea(float x, float y, float r) {
		return (Math.sqrt(Math.pow((this.cX - (x - this.x)), 2)
				+ Math.pow((this.cY - (y - this.y)), 2)) < r) ? true : false;
	}

	private void moveFlag(float x, float y) {
		if (isInArea(x, y, this.outerRadius / 2)) {
			this.pCX = x - this.x;
			this.pCY = y - this.y;
		} else {
			setPointerXY(this.cX, this.cY, this.outerRadius / 2 - 2,
					getRadian(this.cX, this.cY, x - this.x, y - this.y));
		}
	}
}
